package main

import "fmt"

type User2 struct {
	id   int
	name string
}

func (self *User2) Test() {
	fmt.Printf("%p, %v\n", self, self)
}

func (self *User2) TestPointer() {
	fmt.Printf("TestPointer: %p, %v\n", self, self)
}

func (self User2) TestValue() {
	fmt.Printf("TestValue: %p, %v\n", &self, self)
}

func main() {
	demo1MethodExpression()
	demo2ValueMethodExpression()
	demo3ValuePointerMethodExpression()
}

/*
可以直接将某个结构体的方法的表达式获取出来
并可以随时调用
*/
func demo1MethodExpression() {
	u := User2{1, "Tom"}
	u.Test()

	mValue := u.Test // User的方法可以直接获取出来
	mValue()         // 方法调用，隐式传递 receiver

	mExpression := (*User2).Test // 这里获取了一个类型的方法，需要后续调用时传递receiver
	mExpression(&u)              // 方法调用，显式传递 receiver

}

/*
不是指针类型receiver的方法，获取到后本质是复制
*/
func demo2ValueMethodExpression() {
	u := User2{1, "Tom"}
	mValue := u.Test // 立即复制 receiver，因为不是指针类型，不受后续修改影响。

	u.id, u.name = 2, "Jack"
	u.Test() //   {2 Jack}

	mValue() //{1 Tom}
}

func demo3ValuePointerMethodExpression() {
	u := User2{1, "Tom"}
	fmt.Printf("User: %p, %v\n", &u, u)

	mv := User2.TestValue
	mv(u)

	mp := (*User2).TestPointer
	mp(&u)

	mp2 := (*User2).TestValue // *User 方法集包含 TestValue。签名变为 func TestValue(self *User)。实际依然是 receiver value copy。
	mp2(&u)
}
